/**
 * Copyright [2019] [LiBo/Alex of copyright liboware@gmail.com ]
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.hyts.schedule.dynamic.serv.impl;

import com.google.inject.ImplementedBy;
import com.hyts.schedule.dynamic.bean.TaskJob;
import com.hyts.schedule.dynamic.core.SchedulerFactoryBean;
import com.hyts.schedule.dynamic.core.TaskStatelessBean;
import com.hyts.schedule.dynamic.serv.TaskJobService;
import lombok.SneakyThrows;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import java.util.*;

/**
 * @project-name:coffice-toolbox
 * @package-name:com.hyts.schedule.dynamic.serv
 * @author:LiBo/Alex
 * @create-date:2020-04-06 13:44
 * @copyright:libo-alex4java
 * @email:liboware@gmail.com
 * @description:
 */
public class MemoryTaskJobService implements TaskJobService {

    /** 计划任务map */
    private static Map<String, TaskJob> jobMap = new HashMap<>();


    @SneakyThrows
    private static void injectBean(JobKey jobKey, Trigger trigger, Scheduler scheduler, List<TaskJob> jobList){
        TaskJob job = new TaskJob();
        job.setJobName(jobKey.getName());
        job.setJobGroup(jobKey.getGroup());
        job.setDesc("触发器:" + trigger.getKey());
        Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
        job.setJobStatus(triggerState.name());
        if (trigger instanceof CronTrigger) {
            CronTrigger cronTrigger = (CronTrigger) trigger;
            String cronExpression = cronTrigger.getCronExpression();
            job.setCronExpression(cronExpression);
        }
        jobList.add(job);
    }

    @SneakyThrows
    @Override
    public List<TaskJob> getRunningTasks(TaskJob taskJob) {
        Scheduler scheduler = SchedulerFactoryBean.INSTANCE.getNormalScheduleFactory().getScheduler();
        List<JobExecutionContext> executingJobs = scheduler.getCurrentlyExecutingJobs();
        List<TaskJob> jobList = new ArrayList<>(executingJobs.size());
        for (JobExecutionContext executingJob : executingJobs) {
            JobDetail jobDetail = executingJob.getJobDetail();
            JobKey jobKey = jobDetail.getKey();
            Trigger trigger = executingJob.getTrigger();
            injectBean(jobKey,trigger,scheduler,jobList);
        }
        return jobList;
    }

    @SneakyThrows
    @Override
    public List<TaskJob> getPlanTasks(TaskJob taskJob) {
        Scheduler scheduler = SchedulerFactoryBean.INSTANCE.getNormalScheduleFactory().getScheduler();
        GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
        Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
        List<TaskJob> jobList = new ArrayList<>();
        for (JobKey jobKey : jobKeys) {
            List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
            for (Trigger trigger : triggers) {
                injectBean(jobKey,trigger,scheduler,jobList);
            }
        }
        return jobList;
    }

    @Override
    public boolean pauseTask(TaskJob taskJob) {
        try {
            Scheduler scheduler = SchedulerFactoryBean.INSTANCE.getNormalScheduleFactory().getScheduler();
            JobKey jobKey = JobKey.jobKey(taskJob.getJobName(), taskJob.getJobGroup());
            scheduler.pauseJob(jobKey);
            return true;
        } catch (SchedulerException e) {
            return false;
        }
    }

    @Override
    public boolean resumeTask(TaskJob taskJob) {
        try {
            Scheduler scheduler = SchedulerFactoryBean.INSTANCE.getNormalScheduleFactory().getScheduler();
            JobKey jobKey = JobKey.jobKey(taskJob.getJobName(), taskJob.getJobGroup());
            scheduler.resumeJob(jobKey);
            return true;
        } catch (SchedulerException e) {
            return false;
        }
    }

    @Override
    public boolean removeTask(TaskJob taskJob) {
        try {
            Scheduler scheduler = SchedulerFactoryBean.INSTANCE.getNormalScheduleFactory().getScheduler();
            JobKey jobKey = JobKey.jobKey(taskJob.getJobName(), taskJob.getJobGroup());
            return scheduler.deleteJob(jobKey);
        } catch (SchedulerException e) {
            return false;
        }
    }

    @Override
    public boolean runTask(TaskJob taskJob) {
        try {
            Scheduler scheduler = SchedulerFactoryBean.INSTANCE.getNormalScheduleFactory().getScheduler();
            JobKey jobKey = JobKey.jobKey(taskJob.getJobName(), taskJob.getJobGroup());
            scheduler.triggerJob(jobKey);
            return true;
        } catch (SchedulerException e) {
            return false;
        }
    }

    @SneakyThrows
    @Override
    public boolean updateTask(TaskJob taskJob) {
        Scheduler scheduler = SchedulerFactoryBean.INSTANCE.getNormalScheduleFactory().getScheduler();
        TriggerKey triggerKey = TriggerKey.triggerKey(taskJob.getJobName(),
                taskJob.getJobGroup());
//获取trigger，即在spring配置文件中定义的 bean id="myTrigger"
        CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
//表达式调度构建器
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(taskJob
                .getCronExpression());
//按新的cronExpression表达式重新构建trigger
        trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)
                .withSchedule(scheduleBuilder).build();
//按新的trigger重新设置job执行
        return scheduler.rescheduleJob(triggerKey, trigger) != null;
    }

    /**
     * 增添任务
     * @param taskJob
     * @return
     */
    @SneakyThrows
    @Override
    public Scheduler addTask(TaskJob taskJob) {
        Scheduler scheduler = SchedulerFactoryBean.INSTANCE.getNormalScheduleFactory().getScheduler();
        JobDetail jobDetail = JobBuilder.newJob(TaskStatelessBean.class).
                withIdentity(taskJob.getJobName(), taskJob.getJobGroup()).build();
        jobDetail.getJobDataMap().put("scheduleJob", taskJob);
        //表达式调度构建器
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(taskJob.getCronExpression());
        //按新的cronExpression表达式构建一个新的trigger
        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(taskJob.getJobName(), taskJob.getJobGroup()).withSchedule(scheduleBuilder).build();
        scheduler.scheduleJob(jobDetail, trigger) ;
        return scheduler;
    }
}
